package com.demandbreakdown.xiyun.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.demandbreakdown.xiyun.common.constant.SecurityConstant;
import com.demandbreakdown.xiyun.mapper.SpaceMapper;
import com.demandbreakdown.xiyun.model.entity.Space;
import com.demandbreakdown.xiyun.service.SecurityControlService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

import static com.demandbreakdown.xiyun.common.constant.SecurityConstant.*;
import static com.demandbreakdown.xiyun.common.constant.SpaceConstant.INVITE_CODE_EXPIRE_HOURS;

/**
 * 安全控制服务实现类
 *
 * @author poxz
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class SecurityControlServiceImpl implements SecurityControlService {

    // Mapper 层依赖
    private final SpaceMapper spaceMapper;

    // 工具类依赖
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean checkIpRateLimit(String clientIp, String operation) {
        if (clientIp == null || clientIp.trim().isEmpty()) {
            // 无法获取IP时允许通过
            return true;
        }

        String key = IP_RATE_LIMIT_PREFIX + operation + ":" + clientIp;

        try {
            Integer count = (Integer) redisTemplate.opsForValue().get(key);

            if (count == null) {
                // 首次的请求，设置计数器
                redisTemplate.opsForValue().set(key, 1, IP_RATE_LIMIT_WINDOW, TimeUnit.SECONDS);
                return true;
            }

            if (count >= IP_RATE_LIMIT_REQUESTS) {
                log.warn("IP请求频率超限: ip={}, operation={}, count={}", clientIp, operation, count);
                return false;
            }

            // 增加计数
            redisTemplate.opsForValue().increment(key);
            return true;

        } catch (Exception e) {
            log.error("检查IP频率限制异常: {}", e.getMessage());
            // 异常情况下允许通过
            return true;
        }
    }

    @Override
    public boolean checkEmailCaptchaLimit(String email) {
        if (email == null || email.trim().isEmpty()) {
            return true;
        }

        // 检查发送间隔限制
        String intervalKey = EMAIL_RATE_LIMIT_PREFIX + email;
        if (redisTemplate.hasKey(intervalKey)) {
            log.warn("邮箱验证码发送过于频繁: email={}", email);
            return true;
        }

        // 检查每日发送次数限制
        String dailyKey = EMAIL_DAILY_LIMIT_PREFIX + email + ":" +
                (System.currentTimeMillis() / (24 * 60 * 60 * 1000));

        try {
            Object countObj = redisTemplate.opsForValue().get(dailyKey);
            int count = 0;

            if (countObj instanceof Integer) {
                count = (Integer) countObj;
            } else if (countObj instanceof String) {
                try {
                    count = Integer.parseInt((String) countObj);
                } catch (NumberFormatException ignored) {

                }
            }

            if (count >= EMAIL_DAILY_LIMIT) {
                log.warn("邮箱每日验证码发送次数超限: email={}, count={}", email, count);
                return true;
            }

            return false;

        } catch (Exception e) {
            log.error("检查邮箱验证码频率限制异常: {}", e.getMessage());
            // 异常情况下允许通过
            return false;
        }
    }

    @Override
    public void recordEmailCaptchaSent(String email) {
        if (email == null || email.trim().isEmpty()) {
            return;
        }

        try {
            // 设置发送间隔限制
            String intervalKey = EMAIL_RATE_LIMIT_PREFIX + email;
            redisTemplate.opsForValue().set(intervalKey, "1", EMAIL_RATE_LIMIT_SECONDS, TimeUnit.SECONDS);

            // 更新每日发送次数
            String dailyKey = EMAIL_DAILY_LIMIT_PREFIX + email + ":" +
                    (System.currentTimeMillis() / (24 * 60 * 60 * 1000));
            redisTemplate.opsForValue().increment(dailyKey);
            redisTemplate.expire(dailyKey, 24 * 60 * 60, TimeUnit.SECONDS);

        } catch (Exception e) {
            log.error("记录邮箱验证码发送异常: {}", e.getMessage());
        }
    }

    @Override
    public boolean isInviteCodeExpired(Long spaceId, String inviteCode) {
        if (spaceId == null || inviteCode == null || inviteCode.trim().isEmpty()) {
            return true;
        }

        try {
            LambdaQueryWrapper<Space> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Space::getId, spaceId)
                    .eq(Space::getInviteCode, inviteCode);

            Space space = spaceMapper.selectOne(wrapper);
            if (space == null) {
                // 空间不存在或邀请码不匹配
                return true;
            }

            // 检查邀请码创建时间（这里用空间更新时间近似）
            LocalDateTime expireTime = space.getUpdateTime().plusHours(INVITE_CODE_EXPIRE_HOURS);
            boolean expired = LocalDateTime.now().isAfter(expireTime);

            if (expired) {
                log.info("邀请码已过期: spaceId={}, inviteCode={}, expireTime={}",
                        spaceId, inviteCode, expireTime);
            }

            return expired;

        } catch (Exception e) {
            log.error("检查邀请码过期异常: {}", e.getMessage());
            // 异常情况下认为已过期
            return true;
        }
    }

    @Override
    public String getClientRealIp() {
        try {
            ServletRequestAttributes attributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

            if (attributes == null) {
                return SecurityConstant.UNKNOWN_IP;
            }

            HttpServletRequest request = attributes.getRequest();

            // 尝试获取真实IP（考虑代理和负载均衡）
            String ip = request.getHeader("X-Forwarded-For");
            if (ip != null && !ip.isEmpty() && !SecurityConstant.UNKNOWN_IP.equalsIgnoreCase(ip)) {
                // X-Forwarded-For可能包含多个IP，取第一个
                return ip.split(",")[0].trim();
            }

            ip = request.getHeader("X-Real-IP");
            if (ip != null && !ip.isEmpty() && !SecurityConstant.UNKNOWN_IP.equalsIgnoreCase(ip)) {
                return ip;
            }

            ip = request.getHeader("Proxy-Client-IP");
            if (ip != null && !ip.isEmpty() && !SecurityConstant.UNKNOWN_IP.equalsIgnoreCase(ip)) {
                return ip;
            }

            ip = request.getHeader("WL-Proxy-Client-IP");
            if (ip != null && !ip.isEmpty() && !SecurityConstant.UNKNOWN_IP.equalsIgnoreCase(ip)) {
                return ip;
            }

            return request.getRemoteAddr();

        } catch (Exception e) {
            log.error("获取客户端IP异常: {}", e.getMessage());
            return SecurityConstant.UNKNOWN_IP;
        }
    }
}
